iT邦幫忙

2023 iThome 鐵人賽

DAY 6
1
SideProject30

Laravel 擴展宇宙:從 1 到 100 十倍速打造產品獨角獸系列 第 6

#5 API Service 的第三步: 萬事起頭難,但是很重要的資料庫規劃

  • 分享至 

  • xImage
  •  

OrbStack - Mac 上 container 開發的另一個選擇

在開始今天的 API CRUD 進度前,我要介紹一個近期使用的一個工具:OrbStack,快速順暢是我從 Docker desktop 跳過來的第一印象,毫無疑問的最佳替代品,如果你是使用 Mac 在開發有使用到 docker 的話,非常建議更換成 OrbStack。

建立環境變數

在前面我們已經將環境的設定都趨於一致,所以在本地開發前就要開始設定一些參數,首先會遇到的就是環境變數。

這邊我使用的也是 GCP 生態系的工具 - Secret Manager。

GCP Secret Manager 是一個安全且方便的密鑰管理系統,可以用來存儲和管理各種敏感數據。它可以與 Cloud Build 整合,在本地開發時,只需要一段指令就可以很簡單的使用,不會有太多麻煩的整合過程。

新增

# Ref: https://cloud.google.com/secret-manager/docs/create-secret-quickstart#create_a_secret_and_access_a_secret_version
gcloud secrets create api-local \
    --replication-policy="automatic" \
    --data-file=".env"

取得

gcloud beta secrets versions access latest 
    --secret="api-local" > ./.env

更新

這邊實際上是針對 api-local 新增一個修訂版,使用上跟版本控制的邏輯是類似的

gcloud secrets versions add api-local 
    --data-file=".env"

最後請記得,使用工具的同時要研究一下計費方式,可以參考到文件上的敘述

Note: You are billed for both enabled and disabled secret versions. You are not billed for secret versions that are in the destroyed state.
https://cloud.google.com/secret-manager/docs/add-secret-version#states

資料庫規劃與設定

Schema 計畫

根據過往的經驗,schema 會隨進度推進而會有程度不一的變動,所以目前先將基本的 table 先規劃出來。
image alt

Laravel 中的基本設定

以下將比較重要的部分節錄於下:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('episodes', static function (Blueprint $table) {
            $table->uuid('id');
            $table->uuid('channel_id');
            $table->string('guid');
            $table->string('guid_hash', 64);
            $table->string('title');
            $table->jsonb('metadata');
            $table->jsonb('stream_url');
            $table->string('caption_path')->nullable();
            $table->timestampRange('published_range');
            $table->smallInteger('status')->default(0);
            
            $table->timestamps();
            $table->softDeletes();

            $table->index(['channel_id', 'status', 'published_at']);
            $table->unique(['guid_hash']);
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('episodes');
    }
};
<?php

namespace App\Models;

use App\Models\Builder\CommonBuilder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Episode extends Base
{
    use HasFactory;

    protected $casts = [
        'guid' => 'string',
        'title' => 'string',
        'duration' => 'integer',
        'summary' => 'string',
        'metadata' => 'array',
        'stream_url' => 'array',
        'caption' => 'array',
        'published_at' => 'datetime',
        'status' => 'integer',
    ];

    public static function query(): EpisodeBuilder
    {
        return parent::query();
    }

    public function newEloquentBuilder($query): EpisodeBuilder
    {
        return new EpisodeBuilder($query);
    }

    public function channel(): BelongsTo
    {
        return $this->belongsTo(Channel::class);
    }
}
<?php

namespace App\Models\Builder;

use BackedEnum;
use Illuminate\Database\Eloquent\Builder;

class EpisodeBuilder extends Builder
{
    public function isPublished(): self
    {
        return $this->whereStatus(EpisodeStatus::published);
    }
    
    // From common trait in other php file
    public function whereStatus(int|BackedEnum $status): self
    {
        if ($status instanceof BackedEnum) {
            $status = $status->value;
        }

        return $this->where('status', $status);
    }

    public function whereChannelId($id): self
    {
        return $this->where('channel_id', $id);
    }
}
<?php

namespace App\Enum;

enum EpisodeStatus :int
{
    case pending = 0;
    case published = 1;
    case unpublished = 2;
}

就算是在開發時間緊迫的功能開發中,還是會依序將 migrationmodelquery buildermodel factoryhttp respurce 的定義設定完整。這樣可以有效的讓後面的開發上,可以有更快速的測試與驗證的效率,並且減少出錯的機率。

本次使用到的工具

  • dbdiagram
  • Orbstack
  • Laravel + PHP 8.2
  • Roadrunner
  • GCP secret manager

Reference

Notice

以上是這次實作的紀錄,如果有哪個部分需要解釋的部分,可以在留言處留下問題,我會盡量補充。


上一篇
#4 API Service 的第二步: 本地與 Laravel 初始化
下一篇
#6 API Service 的第四步: 在忙也不要忘記加測試
系列文
Laravel 擴展宇宙:從 1 到 100 十倍速打造產品獨角獸30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言